package ui;

import info.Conference;
import info.Manuscript;
import info.Review;
import io.ConferenceAccess;
import io.ReviewAccess;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.text.JTextComponent;

import users.Reviewer;

/**
 * This panel mimics the layout of the review submission form.  It can
 * double as a form to fill out, and as a display for previously submitted
 * forms.
 * 
 * @author Aaron Chen
 * @version 3/6/2014
 */
@SuppressWarnings("serial")
public class ReviewSubmissionPanel extends AbstractForm {
  
  /** The instruction text found near the beginning of the form. */
  private static final String INSTRUCTION_TEXT =
      "Please provide a numeric rating on a 5-point scale for each question, along "
      + "with a brief rationale for each numeric rating. In doing so, please discuss "
      + "both the strengths and the weaknesses of each paper so that the editors and "
      + "authors can understand your reasoning. Please phrase your reviews politely; "
      + "even 'bad' papers represent a lot of work on the part of the authors. The "
      + "review may be the basis for further revisions of the paper or the work that "
      + "the paper reports. We all know how hurtful a needlessly negative review can "
      + "be, and how helpful a positive one can be; please try to bear that in mind "
      + "when you are writing yours. ";
  
  /** The list of radio button evaluations for the author. */
  private static final String[] QUESTION_LIST = {
    "1.  Can the content be directly applied by classroom instructors or curriculum "
      + "designers?",
    "2.  Does the work appeal to a broad readership interested in engineering "
      + "education? (Or is it narrowly specialized?)",
    "3.  Does the work address a significant problem?",
    "4.  Does the author build upon relevant references and bodies of knowledge?",
    "5.  If a teaching intervention is reported, is it adequately evaluated in terms"
      + " of its impact on learning in actual use?",
    "6.  Does the author use methods appropriate to the goals, both for the "
      + "instructional intervention and the evaluation of impact on learning?",
    "7.  Did the author provide sufficient detail to replicate and evaluate?",
    "8.  Is the paper clearly and carefully written?",
    "9.  Does the paper adhere to accepted standards of style, usage, and composition?"
  };
  
  /** The text field for the Reviewer's name. */
  private JTextField my_tf_reviewer_name;
  
  /** The text field for the name of the conference that the manuscript has been
   * submitted to. */
  private JTextField my_tf_conference_name;
  
  /** The text field for the manuscript's author. */
  private JTextField my_tf_manuscript_author;
  
  /** The text field for the manuscript's title. */
  private JTextField my_tf_manuscript_title;
  
  /** The text area for the Reviewer's confidential comments to the Subprogram
   * Chair. */
  private JTextArea my_ta_confidential;
  
  /** The radio button group for the review summary. */
  private ButtonGroup my_group_summary;
  
  /** The radio button groups for the various evaluation categories. */
  private ButtonGroup[] my_button_groups;
  
  /** The text area for the full review. */
  private JTextArea my_ta_full_review;
  
  /** The Reviewer that is filling out the form. */
  private Reviewer my_reviewer;
  
  /** The Review object being represented by this form. */
  private Review my_review;
  
  /** The database access that handles Review objects. */
  private ReviewAccess my_review_access;

  
  /**
   * Initializes the panel with empty fields.
   * @param the_parent The main window.
   */
  public ReviewSubmissionPanel(final DisplayPanel the_parent) {
    super(the_parent);
    my_review_access = MainPage.getDatabase().accessRev();
    my_btn_submit.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        submitForm();
        JOptionPane.showMessageDialog(ReviewSubmissionPanel.this,
                                      "Form submitted successfully!");
        setMode(MODE_EXISTING_FORM);
      }
    });
    my_btn_save_changes.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent the_e) {
        //TODO add a check to see if the the recommendation deadline is past.
        editForm();
        JOptionPane.showMessageDialog(ReviewSubmissionPanel.this,
                                      "Form edited successfully!");
      }
    });
  }
  
  /**
   * Initializes the panel with filled out fields.  Use this constructor if you
   * want to view a form that has been previously filled out.
   * @param the_parent The main window.
   * @param the_r The review form that was filled out previously.
   */
  public ReviewSubmissionPanel(final DisplayPanel the_parent, final Review the_r) {
    this(the_parent);
    setMode(MODE_EXISTING_FORM);
    populateFields(the_r);
  }
  
  /**
   * Initializes the panel with filled out fields.  Use this constructor if you
   * want to view a form that has been previously filled out.
   * @param the_parent The main application window container.
   * @param the_reviewer The reviewer that will fill out this form.
   * @param the_manuscript The manuscript for which this form is being filled out for.
   */
  public ReviewSubmissionPanel(final DisplayPanel the_parent,
                               final Reviewer the_reviewer,
                               final Manuscript the_manuscript) {
    this(the_parent);
    final long conf_id = the_reviewer.getConferenceID();
    final Conference c = MainPage.getDatabase().accessConf().getConference(conf_id);
    my_reviewer = the_reviewer;
    setConferenceFields(c);
    setManuscriptFields(the_manuscript);
    setUserFields(the_reviewer);
  }

  
  /**
   * {@inheritDoc}
   */
  @Override
  protected String getFormTitle() {
    return "Review Submission Form";
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected JPanel createMainPanel() {
    final JPanel panel_main = new JPanel();
    panel_main.setBorder(null);
    panel_main.setBackground(Standards.COLOR_BACKGROUND);
    panel_main.setLayout(new BoxLayout(panel_main, BoxLayout.Y_AXIS));

    panel_main.add(createTitleLabelPanel());
    panel_main.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_main.add(createInstructionsPanel());
    panel_main.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_main.add(createFormPanel());
    panel_main.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_main.add(createButtonsPanel());
    
    return panel_main;
  }
  
  /**
   * Creates the instructions panel that contains instructions for the user.
   * @return The instructions panel.
   */
  private JPanel createInstructionsPanel() {
    final JPanel panel_instructions = new JPanel();
    panel_instructions.setBorder(Standards.BORDER_COMPOUND_FORM);
    panel_instructions.setBackground(Standards.COLOR_BACKGROUND);
    panel_instructions.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_instructions_title = new JLabel("Instructions to Reviewers:");
    lbl_instructions_title.setFont(Standards.FONT_BOLD);
    
    final JTextArea ta_instructions = new JTextArea();
    ta_instructions.setBackground(Standards.COLOR_BACKGROUND);
    ta_instructions.setEditable(false);
    ta_instructions.setFont(Standards.FONT_STANDARD);
    ta_instructions.setWrapStyleWord(true);
    ta_instructions.setLineWrap(true);
    ta_instructions.setText(INSTRUCTION_TEXT);
    ta_instructions.setRows(ta_instructions.getLineCount());

    panel_instructions.add(lbl_instructions_title, BorderLayout.NORTH);
    panel_instructions.add(ta_instructions, BorderLayout.CENTER);
    
    return panel_instructions;
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  protected JPanel createFormPanel() {
    final JPanel panel_form = new JPanel();
    panel_form.setLayout(new BoxLayout(panel_form, BoxLayout.Y_AXIS));
    panel_form.setBackground(Standards.COLOR_BACKGROUND);
    panel_form.setBorder(Standards.BORDER_COMPOUND_FORM);
    
    panel_form.add(createColumnedPanel());
    panel_form.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_LARGE));
    panel_form.add(createConfidentialPanel());
    panel_form.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_LARGE));
    panel_form.add(createAuthorQuestionairePanel());
    panel_form.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_form.add(createSummaryPanel());
    
    return panel_form;
  }
  
  /**
   * Creates the columned portion of the form panel.
   * @return The columned panel.
   */
  private JPanel createColumnedPanel() {
    final JPanel panel_column_split = new JPanel();
    panel_column_split.setBackground(Standards.COLOR_BACKGROUND);
    panel_column_split.setLayout(new BoxLayout(panel_column_split, BoxLayout.X_AXIS));

    panel_column_split.add(createLeftColumnPanel());
    panel_column_split.add(Box.createHorizontalStrut(Standards.STRUT_LENGTH_LARGE));
    panel_column_split.add(createRightColumnPanel());
    
    return panel_column_split;
  }
  
  /**
   * Creates the left column of the columned panel.
   * @return The left column panel.
   */
  private JPanel createLeftColumnPanel() {
    final JPanel panel_left_column = new JPanel();
    panel_left_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_left_column.setLayout(new BoxLayout(panel_left_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_reviewer_name = new JPanel();
    panel_reviewer_name.setBackground(Standards.COLOR_BACKGROUND);
    panel_reviewer_name.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_reviewer_name = new JLabel("Reviewer Name");
    
    my_tf_reviewer_name = new JTextField();
    my_tf_reviewer_name.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_manuscript_author = new JPanel();
    panel_manuscript_author.setBackground(Standards.COLOR_BACKGROUND);
    panel_manuscript_author.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_manuscript_author = new JLabel("Manuscript Author");
    
    my_tf_manuscript_author = new JTextField();
    my_tf_manuscript_author.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    panel_left_column.add(panel_reviewer_name);
    panel_reviewer_name.add(lbl_reviewer_name, BorderLayout.CENTER);
    panel_reviewer_name.add(my_tf_reviewer_name, BorderLayout.SOUTH);
    panel_left_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_left_column.add(panel_manuscript_author);
    panel_manuscript_author.add(lbl_manuscript_author, BorderLayout.CENTER);
    panel_manuscript_author.add(my_tf_manuscript_author, BorderLayout.SOUTH);
    
    return panel_left_column;
  }
  
  /**
   * Creates the right column of the columned panel.
   * @return The right column panel.
   */
  private JPanel createRightColumnPanel() {
    final JPanel panel_right_column = new JPanel();
    panel_right_column.setBackground(Standards.COLOR_BACKGROUND);
    panel_right_column.setLayout(new BoxLayout(panel_right_column, BoxLayout.Y_AXIS));
    
    final JPanel panel_conference = new JPanel();
    panel_conference.setBackground(Standards.COLOR_BACKGROUND);
    panel_conference.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_conference_name = new JLabel("Conference Name");
    
    my_tf_conference_name = new JTextField();
    my_tf_conference_name.setColumns(Standards.TEXT_BOX_HALF_WIDTH);
    
    final JPanel panel_manuscript_title = new JPanel();
    panel_manuscript_title.setBackground(Standards.COLOR_BACKGROUND);
    panel_manuscript_title.setLayout(new BorderLayout(0, 0));
    
    final JLabel lbl_manuscript_title = new JLabel("Manuscript Title");
    
    my_tf_manuscript_title = new JTextField();
    my_tf_manuscript_title.setColumns(Standards.TEXT_BOX_HALF_WIDTH);

    panel_right_column.add(panel_conference);
    panel_conference.add(lbl_conference_name, BorderLayout.CENTER);
    panel_conference.add(my_tf_conference_name, BorderLayout.SOUTH);
    panel_right_column.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    panel_right_column.add(panel_manuscript_title);
    panel_manuscript_title.add(lbl_manuscript_title, BorderLayout.CENTER);
    panel_manuscript_title.add(my_tf_manuscript_title, BorderLayout.SOUTH);
    
    return panel_right_column;
  }
  
  /**
   * Creates the confidential panel, where the Reviewer can give private
   * comments to the Subprogram Chair without it ever becoming public
   * once the Program Chair makes his decision on the manuscript.
   * @return The confidential panel.
   */
  private JPanel createConfidentialPanel() {
    final JPanel panel_confidential = new JPanel(new BorderLayout());
    panel_confidential.setBackground(Standards.COLOR_BACKGROUND);

    final JLabel lbl_confidential = new JLabel("Confidential Comments "
                                               + "to the Subprogram Chair");
    lbl_confidential.setFont(Standards.FONT_MEDIUM);
    
    my_ta_confidential = new JTextArea();
    my_ta_confidential.setWrapStyleWord(true);
    my_ta_confidential.setRows(Standards.TEXT_AREA_MEDIUM_ROWS);
    my_ta_confidential.setLineWrap(true);
    
    panel_confidential.add(lbl_confidential, BorderLayout.CENTER);
    panel_confidential.add(createScrollPane(my_ta_confidential), BorderLayout.SOUTH);
    
    return panel_confidential;
  }
  
  /**
   * Creates the questionnaire radio button groups for the reviewer to evaluate
   * the manuscript with.
   * @return The questionnaire panel.
   */
  private JPanel createAuthorQuestionairePanel() {
    final JPanel panel_questionaire = new JPanel(new BorderLayout());
    panel_questionaire.setBackground(Standards.COLOR_BACKGROUND);
    
    final JLabel lbl_questionaire = new JLabel("Comments to the Author");
    lbl_questionaire.setFont(Standards.FONT_MEDIUM);
    
    panel_questionaire.add(lbl_questionaire, BorderLayout.CENTER);
    
    final JPanel panel_questions = new JPanel();
    panel_questions.setLayout(new BoxLayout(panel_questions, BoxLayout.Y_AXIS));
    panel_questions.setBackground(Standards.COLOR_BACKGROUND);
    panel_questions.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));
    
    my_button_groups = new ButtonGroup[QUESTION_LIST.length];
    for (int i = 0; i < my_button_groups.length; i++) {
      my_button_groups[i] = new ButtonGroup();
      panel_questions.add(createRadioButtonQuestion(QUESTION_LIST[i], my_button_groups[i]));
    }
    
    panel_questionaire.add(panel_questions, BorderLayout.SOUTH);
    
    return panel_questionaire;
  }
  
  /**
   * Creates the summary panel; the summary of the Reviewer's review.
   * @return The summary panel.
   */
  private JPanel createSummaryPanel() {
    final JPanel panel_summary = new JPanel(new BorderLayout());
    panel_summary.setBackground(Standards.COLOR_BACKGROUND);

    final JLabel lbl_questionaire = new JLabel("Summary");
    lbl_questionaire.setFont(Standards.FONT_MEDIUM);
    
    final JPanel panel_sub_summary = new JPanel();
    panel_sub_summary.setLayout(new BoxLayout(panel_sub_summary, BoxLayout.Y_AXIS));
    panel_sub_summary.setBackground(Standards.COLOR_BACKGROUND);
    panel_sub_summary.add(Box.createVerticalStrut(Standards.STRUT_LENGTH_MEDIUM));

    my_group_summary = new ButtonGroup();
    panel_sub_summary.add(createRadioButtonQuestion("Summary Rating", my_group_summary));
    
    final JPanel panel_full_review = new JPanel(new BorderLayout());
    panel_full_review.setBackground(Standards.COLOR_BACKGROUND);
    
    final JLabel lbl_summary_comments = new JLabel("Summary Comments");
    
    my_ta_full_review = new JTextArea();
    my_ta_full_review.setToolTipText("This helps the Subprogram Chair and the author "
                                     + "know how you came to your conclusions.");
    my_ta_full_review.setWrapStyleWord(true);
    my_ta_full_review.setRows(Standards.TEXT_AREA_LARGE_ROWS);
    my_ta_full_review.setLineWrap(true);

    panel_full_review.add(lbl_summary_comments, BorderLayout.CENTER);
    panel_full_review.add(createScrollPane(my_ta_full_review), BorderLayout.SOUTH);

    panel_sub_summary.add(panel_full_review);
    
    panel_summary.add(lbl_questionaire, BorderLayout.CENTER);
    panel_summary.add(panel_sub_summary, BorderLayout.SOUTH);
    
    return panel_summary;
  }
  

  /**
   * Completes the Review submission form and submits it to the database.
   * @return The Review.
   */
  private Review submitForm() {
    final Review r = inputToReview();
    my_review_access.createReview(r);
    my_review = r;
    return r;
  }
  
  /**
   * Edits the Review and submits the changes to the database.
   * @return The Review.
   */
  private Review editForm() {
    final Review r = inputToReview();
    r.setID(my_review.getID());
    my_review_access.editReview(r);
    return r;
  }
  
  /**
   * Converts form input into a Review object.
   * @return The Review.
   */
  private Review inputToReview() {
    final List<String> field_values = new ArrayList<String>();
    field_values.add(my_tf_reviewer_name.getText());
    if (my_reviewer == null) {
      field_values.add("0");
    } else {
      field_values.add(Long.toString(my_reviewer.getConferenceID()));
    }
    field_values.add(my_tf_manuscript_author.getText());
    field_values.add(my_tf_manuscript_title.getText());
    final int[] ratings = new int[QUESTION_LIST.length];
    for (int i = 0; i < ratings.length; i++) {
      ratings[i] = getRadioButtonIndexInGroup(my_button_groups[i]);
    }
    final int summary = getRadioButtonIndexInGroup(my_group_summary);
    //TODO Hook this up with DataAccess so that the resulting form can exist in a
    //persistent state.  If quick testing is needed, just put the form in a static
    //location and then construct a new panel with the form as a parameter.
    return new Review(0, field_values, my_ta_confidential.getText(),
                      ratings, summary, my_ta_full_review.getText());
  }
  
  /**
   * Populates the form using a previously filled out form.
   * @param the_r The manuscript that was previously submitted.
   */
  private void populateFields(final Review the_r) {
    my_tf_reviewer_name.setText(the_r.getReviewerName());
    final ConferenceAccess database = MainPage.getDatabase().accessConf();
    final String title = database.getConference(the_r.getConferenceID()).getTitle();
    my_tf_conference_name.setText(title);
    my_tf_manuscript_author.setText(the_r.getManuscriptAuthor());
    my_tf_manuscript_title.setText(the_r.getManuscriptTitle());
    my_ta_confidential.setText(the_r.getConfidentialComments());
    final int[] ratings = the_r.getQuestionaireRatings();
    final int max = Math.min(ratings.length, my_button_groups.length);
    for (int i = 0; i < max; i++) {
      setRadioButtonInGroup(my_button_groups[i], ratings[i]);
    }
    setRadioButtonInGroup(my_group_summary, the_r.getSummaryRating());
    my_ta_full_review.setText(the_r.getSummary());
  }
  
  /**
   * {@inheritDoc}
   */
  @Override
  public String getPanelLabel() {
    return "Review";
  }
  
  /**
   * Sets the parameters dependent on the user filling out the form.
   * @param the_reviewer The Reviewer data object.
   */
  private void setUserFields(final Reviewer the_reviewer) {
    lockInText(my_tf_reviewer_name, the_reviewer.getUser().getFullName());
  }
  
  /**
   * Sets the parameters dependent on the conference that the user is filling
   * out the form for.
   * @param the_conference The Conference data object.
   */
  private void setConferenceFields(final Conference the_conference) {
    lockInText(my_tf_conference_name, the_conference.getTitle());
  }
  
  /**
   * Sets the parameters dependent on the conference that the user is filling
   * out the form for.
   * @param the_manuscript The Manuscript data object.
   */
  private void setManuscriptFields(final Manuscript the_manuscript) {
    lockInText(my_tf_manuscript_title, the_manuscript.getTitle());
    lockInText(my_tf_manuscript_author, the_manuscript.getSubmittingAuthor());
  }
  
  /**
   * Sets the text of the text field and then makes it uneditable.
   * @param the_field The text component to set the text for.
   * @param the_str   The String to be displayed.
   */
  private void lockInText(final JTextComponent the_field, final String the_str) {
    the_field.setText(the_str);
    the_field.setEditable(false);
  }
  
}
